/*
 * sdnand.c
 *
 *  Created on: Nov 28, 2024
 *      Author: 18050
 */
#include "sd_nand.h"
#include <stdio.h>
#include <stdlib.h>
#include "string.h"
#include "../delay/delay.h"


SD_HandleTypeDef g_sdcard_handle;             /* SD卡句柄 */
DMA_HandleTypeDef hdma_sdio;				  /* DMA句柄 */
HAL_SD_CardInfoTypeDef g_sd_card_info_handle; /* SD卡信息结构体 */


/**
 * @brief       初始化SD卡
 * @param       无
 * @retval      返回值:0 初始化正确；其他值，初始化错误
 */
uint8_t sd_init(void)
{
    uint8_t SD_Error;

    /* 初始化时的时钟不能大于400KHZ */
    g_sdcard_handle.Instance = SDIO;
    g_sdcard_handle.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;                       /* 上升沿 */
    g_sdcard_handle.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;                  /* 不使用bypass模式，直接用HCLK进行分频得到SDIO_CK */
    g_sdcard_handle.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;           /* 空闲时不关闭时钟电源 */
    g_sdcard_handle.Init.BusWide = SDIO_BUS_WIDE_1B;                               /* 1位数据线 */
    g_sdcard_handle.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; /* 关闭硬件流控 */
    g_sdcard_handle.Init.ClockDiv = 4;                                 		   /* SD传输时钟频率最大25MHZ */

    SD_Error = HAL_SD_Init(&g_sdcard_handle);
    if (SD_Error != HAL_OK)
    {
        return 1;
    }

    HAL_SD_GetCardInfo(&g_sdcard_handle, &g_sd_card_info_handle);                  /* 获取SD卡信息 */

    SD_Error = HAL_SD_ConfigWideBusOperation(&g_sdcard_handle, SDIO_BUS_WIDE_4B);  /* 使能宽总线模式 */
    if (SD_Error != HAL_OK)
    {
        return 2;
    }

    return 0;
}

/**
 * @brief       SDIO底层驱动，时钟使能，引脚配置
                此函数会被HAL_SD_Init()调用
 * @param       hsd  : SD卡句柄
 * @retval      无
 */
void HAL_SD_MspInit(SD_HandleTypeDef *hsd)
{
    if (hsd->Instance == SDIO)
    {
        GPIO_InitTypeDef gpio_init_struct;

        __HAL_RCC_SDIO_CLK_ENABLE();                        /* 使能SDIO时钟 */

        SD_D0_GPIO_CLK_ENABLE();                            /* D0引脚IO时钟使能 */
        SD_D1_GPIO_CLK_ENABLE();                            /* D1引脚IO时钟使能 */
        SD_D2_GPIO_CLK_ENABLE();                            /* D2引脚IO时钟使能 */
        SD_D3_GPIO_CLK_ENABLE();                            /* D3引脚IO时钟使能 */
        SD_CLK_GPIO_CLK_ENABLE();                           /* CLK引脚IO时钟使能 */
        SD_CMD_GPIO_CLK_ENABLE();                           /* CMD引脚IO时钟使能 */

        /* SD_D0引脚模式设置 */
        gpio_init_struct.Pin = SD_D0_GPIO_PIN;
        gpio_init_struct.Mode = GPIO_MODE_AF_PP;            /* 推挽复用 */
        gpio_init_struct.Pull = GPIO_PULLUP;                /* 上拉 */
        gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;      /* 高速 */
        gpio_init_struct.Alternate = GPIO_AF12_SDIO;        /* 复用为SDIO */
        HAL_GPIO_Init(SD_D0_GPIO_PORT, &gpio_init_struct);  /* 初始化 */

        /* SD_D1引脚模式设置 */
        gpio_init_struct.Pin = SD_D1_GPIO_PIN;
        HAL_GPIO_Init(SD_D1_GPIO_PORT, &gpio_init_struct);  /* 初始化 */
        /* SD_D2引脚模式设置 */
        gpio_init_struct.Pin = SD_D2_GPIO_PIN;
        HAL_GPIO_Init(SD_D2_GPIO_PORT, &gpio_init_struct);  /* 初始化 */
        /* SD_D3引脚模式设置 */
        gpio_init_struct.Pin = SD_D3_GPIO_PIN;
        HAL_GPIO_Init(SD_D3_GPIO_PORT, &gpio_init_struct);  /* 初始化 */
        /* SD_CLK引脚模式设置 */
        gpio_init_struct.Pin = SD_CLK_GPIO_PIN;
        HAL_GPIO_Init(SD_CLK_GPIO_PORT, &gpio_init_struct); /* 初始化 */
        /* SD_CMD引脚模式设置 */
        gpio_init_struct.Pin = SD_CMD_GPIO_PIN;
        HAL_GPIO_Init(SD_CMD_GPIO_PORT, &gpio_init_struct); /* 初始化 */
        /* SDIO DMA Init */
        hdma_sdio.Instance = DMA2_Stream3;
        hdma_sdio.Init.Channel = DMA_CHANNEL_4;
        hdma_sdio.Init.Direction = DMA_PERIPH_TO_MEMORY;
        hdma_sdio.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_sdio.Init.MemInc = DMA_MINC_ENABLE;
        hdma_sdio.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
        hdma_sdio.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
        hdma_sdio.Init.Mode = DMA_PFCTRL;
        hdma_sdio.Init.Priority = DMA_PRIORITY_LOW;
        hdma_sdio.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
        hdma_sdio.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
        hdma_sdio.Init.MemBurst = DMA_MBURST_INC4;
        hdma_sdio.Init.PeriphBurst = DMA_PBURST_INC4;
        if (HAL_DMA_Init(&hdma_sdio) != HAL_OK)
        {
            Error_Handler();
        }

        /* Several peripheral DMA handle pointers point to the same DMA handle.
        Be aware that there is only one stream to perform all the requested DMAs. */
        /* Be sure to change transfer direction before calling
        HAL_SD_ReadBlocks_DMA or HAL_SD_WriteBlocks_DMA. */
        __HAL_LINKDMA(hsd,hdmarx,hdma_sdio);
        __HAL_LINKDMA(hsd,hdmatx,hdma_sdio);

        /* SDIO interrupt Init */
        HAL_NVIC_SetPriority(SDIO_IRQn, 0, 0);
        HAL_NVIC_EnableIRQ(SDIO_IRQn);

    }
}

/**
 * @brief       获取卡信息函数
 * @param       cardinfo   : SD卡信息句柄
 * @retval      返回值:读取卡信息状态值
 */
uint8_t get_sd_card_info(HAL_SD_CardInfoTypeDef *cardinfo)
{
    uint8_t sta;
    sta = HAL_SD_GetCardInfo(&g_sdcard_handle, cardinfo);
    return sta;
}

/**
 * @brief       判断SD卡是否可以传输(读写)数据
 * @param       无
 * @retval      返回值:SD_TRANSFER_OK      传输完成，可以继续下一次传输
                       SD_TRANSFER_BUSY SD 卡正忙，不可以进行下一次传输
 */
uint8_t get_sd_card_state(void)
{
    return ((HAL_SD_GetCardState(&g_sdcard_handle) == HAL_SD_CARD_TRANSFER) ? SD_TRANSFER_OK : SD_TRANSFER_BUSY);
}

/**
 * @brief       读SD卡(fatfs/usb调用)
 * @param       pbuf  : 数据缓存区
 * @param       saddr : 扇区地址
 * @param       cnt   : 扇区个数
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
uint8_t sd_read_disk(uint8_t *pbuf, uint32_t saddr, uint32_t cnt)
{
    uint8_t sta = HAL_OK;
    uint32_t timeout = SD_TIMEOUT;
    long long lsector = saddr;
//    sys_intx_disable();
//    __ASM volatile("cpsid i");  /* 关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!) */
//    sta = HAL_SD_ReadBlocks(&g_sdcard_handle, (uint8_t *)pbuf, lsector, cnt, SD_TIMEOUT);  /* 多个sector的读操作 */
    sta = HAL_SD_ReadBlocks_DMA(&g_sdcard_handle, (uint8_t *)pbuf, lsector, cnt);  /* 多个sector的读操作 */
    /* 等待SD卡读完 */
    while (get_sd_card_state() != SD_TRANSFER_OK)
    {
        if (timeout-- == 0)
        {
            sta = SD_TRANSFER_BUSY;
        }
    }
//    sys_intx_enable();     /* 开启总中断 */
//   __ASM volatile("cpsie i");/* 开启总中断(POLLING模式,严禁中断打断SDIO读写操作!!!) */
    return sta;
}

/**
 * @brief       写SD卡(fatfs/usb调用)
 * @param       pbuf  : 数据缓存区
 * @param       saddr : 扇区地址
 * @param       cnt   : 扇区个数
 * @retval      0, 正常;  其他, 错误代码(详见SD_Error定义);
 */
uint8_t sd_write_disk(uint8_t *pbuf, uint32_t saddr, uint32_t cnt)
{
    uint8_t sta = HAL_OK;
    uint32_t timeout = SD_TIMEOUT;
    long long lsector = saddr;
//    sys_intx_disable();
//    __ASM volatile("cpsid i");  /* 关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!) *//* 关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!) */
//    sta = HAL_SD_WriteBlocks(&g_sdcard_handle, (uint8_t *)pbuf, lsector, cnt, SD_TIMEOUT);  /* 多个sector的写操作 */
    sta = HAL_SD_WriteBlocks_DMA(&g_sdcard_handle, (uint8_t *)pbuf, lsector, cnt);
    /* 等待SD卡写完 */
    while (get_sd_card_state() != SD_TRANSFER_OK)
    {
        if (timeout-- == 0)
        {
            sta = SD_TRANSFER_BUSY;
        }
    }
//    __ASM volatile("cpsie i");/* 开启总中断(POLLING模式,严禁中断打断SDIO读写操作!!!) */
//    sys_intx_enable();     /* 开启总中断 */

    return sta;
}
/**
 * @brief       通过串口打印SD卡相关信息
 * @param       无
 * @retval      无
 */
void show_sdcard_info(void)
{
    HAL_SD_CardCIDTypeDef sd_card_cid;

    HAL_SD_GetCardCID(&g_sdcard_handle, &sd_card_cid);        /* 获取CID */
    get_sd_card_info(&g_sd_card_info_handle);                 /* 获取SD卡信息 */

    switch (g_sd_card_info_handle.CardType)
    {
        case CARD_SDSC:
        {
            if (g_sd_card_info_handle.CardVersion == CARD_V1_X)
            {
                printf("Card Type:SDSC V1\r\n");
            }
            else if (g_sd_card_info_handle.CardVersion == CARD_V2_X)
            {
                printf("Card Type:SDSC V2\r\n");
            }
        }
        break;

        case CARD_SDHC_SDXC:
            printf("Card Type:SDHC\r\n");
            break;
        default: break;
    }

    printf("Card ManufacturerID:%d\r\n", sd_card_cid.ManufacturerID);                   /* 制造商ID */
    printf("Card RCA:%d\r\n", g_sd_card_info_handle.RelCardAdd);                        /* 卡相对地址 */
    printf("Card Capacity:%d MB\r\n", (uint32_t)SD_TOTAL_SIZE_MB(&g_sdcard_handle));    /* 显示容量 */
    printf("Card BlockSize:%d\r\n\r\n", g_sd_card_info_handle.BlockSize);               /* 显示块大小 */
}
